package com.hyk.service.impl;

import cn.hutool.core.lang.Snowflake;
import cn.hutool.core.util.RandomUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.exceptions.ApiException;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hyk.config.IdAutoConfiguration;
import com.hyk.domain.User;
import com.hyk.domain.UserAuthAuditRecord;
import com.hyk.domain.UserAuthInfo;
import com.hyk.dto.UserDto;
import com.hyk.geetest.GeetestAutoConfiguration;
import com.hyk.geetest.GeetestLib;
import com.hyk.mapper.UserMapper;
import com.hyk.model.ChangePasswordVo;
import com.hyk.model.UpdateUserMobileVo;
import com.hyk.service.UserAuthAuditRecordService;
import com.hyk.service.UserAuthInfoService;
import com.hyk.service.UserService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import javax.xml.bind.ValidationException;
import java.io.Serializable;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService{

    private Snowflake snowflake = new Snowflake(1,1);

    @Resource
    private UserAuthAuditRecordService userAuthAuditRecordService;

    @Autowired
    private GeetestLib geetestLib;

    @Autowired
    private UserAuthInfoService userAuthInfoService;

    @Autowired
    private RedisTemplate<String,Object> redisTemplate;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateUserAuthStatus(Long id, Byte authStatus, Long authCode, String remark) {
        User user = new User();
        user.setId(id);
        user.setReviewsStatus(authStatus.intValue());
        if(authStatus.equals((byte)1)){
            user.setAuthStatus((byte)2);
        }
        updateById(user);

        UserAuthAuditRecord userAuthAuditRecord = new UserAuthAuditRecord();
        userAuthAuditRecord.setUserId(id);
        userAuthAuditRecord.setStatus(authStatus);
        userAuthAuditRecord.setAuthCode(authCode);
        userAuthAuditRecord.setStep((byte)2l);
        String usrStr = SecurityContextHolder.getContext().getAuthentication().getPrincipal().toString();
        userAuthAuditRecord.setAuditUserId(Long.parseLong(usrStr));
        userAuthAuditRecord.setAuditUserName("test");//todo 远程调用
        userAuthAuditRecord.setRemark(remark);
        userAuthAuditRecord.setId(snowflake.nextId());

        userAuthAuditRecordService.save(userAuthAuditRecord);
    }

    @Override
    public void authAccount(User user) throws ValidationException {
        //极验
        GeetestAutoConfiguration.checkGeetest(user,redisTemplate,geetestLib);

        //校验身份证
        Boolean check = IdAutoConfiguration.check(user.getIdCard(),user.getRealName());
        if (!check){
            throw new ValidationException("身份校验失败！！！");
        }
        //更新数据
        String userId = SecurityContextHolder.getContext().getAuthentication().getPrincipal().toString();
        user.setAuthStatus((byte)1);
        user.setAuthtime(new Date());
        user.setId(Long.parseLong(userId));
        updateById(user);

    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void authUser(String[] imgas) {
        //1.改变user auth_status
        long userId = Long.parseLong(SecurityContextHolder.getContext().getAuthentication().getPrincipal().toString());
        User user = getById(userId);
        user.setReviewsStatus(0);
        updateById(user);

        long authCode = snowflake.nextId();
        //2.添加数据到user_auth
        List<UserAuthInfo> userAuthInfos = new ArrayList<>();
        for(int i =0;i<imgas.length; i++){
            UserAuthInfo userAuthInfo = new UserAuthInfo();
            userAuthInfo.setImageUrl(imgas[i]);
            userAuthInfo.setSerialno(i);
            userAuthInfo.setAuthCode(authCode);
            userAuthInfo.setId(snowflake.nextId());
            userAuthInfo.setUserId(userId);
            userAuthInfo.setCreated(new Date());
            userAuthInfo.setLastUpdateTime(new Date());
            userAuthInfos.add(userAuthInfo);
        }
        userAuthInfoService.saveBatch(userAuthInfos);
    }

    @Override
    public void updatePhone(UpdateUserMobileVo updateUserMobileVo) {
        String userId = SecurityContextHolder.getContext().getAuthentication().getPrincipal().toString();
        User user = getById(userId);

        //验证旧手机验证码
        String oldV = redisTemplate.opsForValue().get("SMS:VERIFY_OLD_PHONE:" + user.getMobile()).toString();
        if (StringUtils.isEmpty(oldV)){
            throw new ApiException("验证码过期");
        }
        if (!oldV.equals(updateUserMobileVo.getOldValidateCode())){
            throw new ApiException("验证码错误");
        }
        //验证新手机验证码
        String newV = redisTemplate.opsForValue().get("SMS:VERIFY_NEW_PHONE:" + updateUserMobileVo.getNewMobilePhone()).toString();
        if (StringUtils.isEmpty(newV)){
            throw new ApiException("验证码过期");
        }
        if (!newV.equals(updateUserMobileVo.getValidateCode())){
            throw new ApiException("验证码错误");
        }

        user.setMobile(updateUserMobileVo.getNewMobilePhone());
        user.setLastUpdateTime(new Date());
        updateById(user);

    }

    @Override
    public Boolean changePassword(ChangePasswordVo changePasswordVo) {
        BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();

        String userId = SecurityContextHolder.getContext().getAuthentication().getPrincipal().toString();
        User user = getById(userId);

        //获取redis中的验证码
        String redisV = (String) redisTemplate.opsForValue().get("SMS:CHANGE_LOGIN_PWD_VERIFY:" + user.getMobile());
        //校验验证码
        if (StringUtils.isEmpty(redisV)){
            throw new ApiException("验证码过期");
        }
        if (!redisV.equals(changePasswordVo.getValidateCode())){
            throw new ApiException("验证码错误");
        }
        //校验旧密码
        boolean matches = bCryptPasswordEncoder.matches(changePasswordVo.getOldpassword(), user.getPassword());
        if (!matches){
            throw new ApiException("旧密码错误！！！");
        }
        //修改密码为新密码
        user.setPassword(bCryptPasswordEncoder.encode(changePasswordVo.getNewpassword()));
        user.setLastUpdateTime(new Date());
        boolean update = updateById(user);
        if (update) {
            return true;
        }
        return false;
    }

    @Override
    public Boolean changePayPassword(ChangePasswordVo changePasswordVo) {
        BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();

        String userId = SecurityContextHolder.getContext().getAuthentication().getPrincipal().toString();
        User user = getById(userId);

        //获取redis中的验证码
        String redisV = (String) redisTemplate.opsForValue().get("SMS:CHANGE_PAY_PWD_VERIFY:" + user.getMobile());
        //校验验证码
        if (StringUtils.isEmpty(redisV)){
            throw new ApiException("验证码过期");
        }
        if (!redisV.equals(changePasswordVo.getValidateCode())){
            throw new ApiException("验证码错误");
        }
        //校验旧密码
        boolean matches = bCryptPasswordEncoder.matches(changePasswordVo.getOldpassword(), user.getPaypassword());
        if (!matches){
            throw new ApiException("旧密码错误！！！");
        }
        //修改密码为新密码
        user.setPaypassword(bCryptPasswordEncoder.encode(changePasswordVo.getNewpassword()));
        user.setLastUpdateTime(new Date());
        boolean update = updateById(user);
        if (update) {
            return true;
        }
        return false;
    }

    @Override
    public Boolean rePayPassword(ChangePasswordVo changePasswordVo) {
        BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();

        String userId = SecurityContextHolder.getContext().getAuthentication().getPrincipal().toString();
        User user = getById(userId);

        //获取redis中的验证码
        String redisV = (String) redisTemplate.opsForValue().get("SMS:FORGOT_PAY_PWD_VERIFY:" + user.getMobile());
        //校验验证码
        if (StringUtils.isEmpty(redisV)){
            throw new ApiException("验证码过期");
        }
        if (!redisV.equals(changePasswordVo.getValidateCode())){
            throw new ApiException("验证码错误");
        }
        //修改密码为新密码
        user.setPaypassword(bCryptPasswordEncoder.encode(changePasswordVo.getPayPassword()));
        user.setLastUpdateTime(new Date());
        boolean update = updateById(user);
        if (update) {
            return true;
        }
        return false;
    }

    @Override
    public Map<Long, UserDto> getBasicUsers(List<Long> ids,String mobile,String username) {
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        if(CollectionUtils.isEmpty(ids) && StringUtils.isBlank(mobile) && StringUtils.isBlank(username)){
            return null;
        }
        if(!CollectionUtils.isEmpty(ids)){
            wrapper.in("id",ids);
        }
        if(StringUtils.isNotBlank(mobile)){
            wrapper.eq("mobile",mobile);
        }
        if(StringUtils.isNotBlank(username)){
            wrapper.eq("username",username);
        }
        List<User> list = list(wrapper);
        List<UserDto> userDtoList = list.stream().map(user ->{
            UserDto userDto = new UserDto();
            BeanUtils.copyProperties(user,userDto);
            return userDto;
        }).collect(Collectors.toList());
        Map<Long, UserDto> map = new HashMap<>();
        for (UserDto userDto:userDtoList) {
            map.put(userDto.getId(),userDto);
        }
        return map;
    }

    @Override
    public void register(User user) throws ValidationException {
        //极验
        GeetestAutoConfiguration.checkGeetest(user,redisTemplate,geetestLib);
        //校验手机或者邮箱是否被注册
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        if (StringUtils.isBlank(user.getMobile())){
            wrapper.eq("mobile",user.getMobile());
        }
        if (StringUtils.isBlank(user.getEmail())){
            wrapper.eq("email",user.getEmail());
        }
        if (!CollectionUtils.isEmpty(list(wrapper))){
            throw new ApiException("手机号或邮箱已被注册");
        }
        //添加邀请关系
        String inviteCode = user.getInviteCode();
        if (!StringUtils.isEmpty(inviteCode)) {
            //查询邀请人
            QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
            userQueryWrapper.eq("invite_code",inviteCode);
            User one = getOne(userQueryWrapper);
            if (one == null) {
                throw new ApiException("邀请码错误");
            }
            user.setInviteRelation(inviteCode);
            user.setDirectInviteid(one.getId().toString());
        }
        //注册用户【添加数据】
        String encodePwd = new BCryptPasswordEncoder().encode(user.getPassword());
        user.setPassword(encodePwd);
        user.setStatus((byte) 1);
        user.setType((byte) 1);
        user.setAuthStatus((byte) 0);
        user.setLogins(0);
        user.setReviewsStatus(-1);
        user.setInviteCode(RandomUtil.randomString(6)); // 用户的邀请码
        user.setCreated(new Date());
        user.setLastUpdateTime(new Date());
        save(user);
    }

    @Override
    public User getById(Serializable id) {
        User user = super.getById(id);

        if(user==null){
            throw new IllegalArgumentException("请输入正确的用户Id") ;
        }
        Byte seniorAuthStatus = null ; // 用户的高级认证状态
        String seniorAuthDesc = "" ;// 用户的高级认证未通过,原因
        Integer reviewsStatus = user.getReviewsStatus(); // 用户被审核的状态 1通过,2拒绝,0,待审核"
        if(reviewsStatus == -1){ //为-1 时,代表用户的资料没有上传
            seniorAuthStatus = 3 ;
            seniorAuthDesc = "资料未填写" ;
        }else {
            switch (reviewsStatus) {
                case 1:
                    seniorAuthStatus = 1;
                    seniorAuthDesc = "审核通过";
                    break;
                case 2:
                    seniorAuthStatus = 2;
                    // 查询被拒绝的原因--->审核记录里面的
                    // 时间排序,
                    List<UserAuthAuditRecord> userAuthAuditRecordList = userAuthAuditRecordService.getUserAuthAuditRecordList(user.getId().toString());
                    if (!CollectionUtils.isEmpty(userAuthAuditRecordList)) {
                        UserAuthAuditRecord userAuthAuditRecord = userAuthAuditRecordList.get(0);
                        seniorAuthDesc = userAuthAuditRecord.getRemark();
                    }else {
                        seniorAuthDesc = "原因未知";
                    }
                    break;
                case 0:
                    seniorAuthStatus = 0;
                    seniorAuthDesc = "等待审核";
                    break;

            }
        }
        user.setSeniorAuthStatus(seniorAuthStatus);
        user.setSeniorAuthDesc(seniorAuthDesc);
        return user;
    }

}
